#pragma once
#include "Socket.h"
#include<sys/epoll.h>

class EpollServer
{
private:
    int listenSock_;
    int port_;
    int epfd_;//epoll模型
private:
    void AddEvent(int sock,size_t event)
    {
        struct epoll_event ev;
        ev.events = event;
        ev.data.fd = sock;
        epoll_ctl(epfd_,EPOLL_CTL_ADD,sock,&ev);
    }
    void DelEvent(int sock)
    {
        epoll_ctl(epfd_,EPOLL_CTL_DEL,sock,nullptr);
    }
    void HandlerEvent(struct epoll_event revs[],int num)
    {
        for(int i = 0; i < num; ++i)
        {
            int fd = revs[i].data.fd;
            if(fd == listenSock_ && revs[i].events&EPOLLIN)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                int sock = accept(listenSock_,(struct sockaddr*)&peer,&len);
                if(sock < 0)
                {
                    std::cerr << "accept error" << std::endl;
                    continue;
                }
                std::string client_ip = inet_ntoa(peer.sin_addr);
                int client_port = ntohs(peer.sin_port);
                std::cout << "Get a new link[" << client_ip << ":" << client_port << std::endl;
                AddEvent(sock,EPOLLIN);
            }
            else if(revs[i].events&EPOLLIN)
            {
                char buffer[128];
                int size = read(fd,buffer,sizeof(buffer)-1);
                if(size > 0)
                {
                    buffer[size-2] = '\0';//telnet下的特殊处理
                    std::cout << "echo:" << buffer << std::endl;
                }
                else if(size == 0)
                {
                    std::cout << "client quit" << std::endl;
                    close(fd);
                    DelEvent(fd);
                }
                else
                {
                    std::cout << "read error" << std::endl;
                    close(fd);
                    DelEvent(fd);
                }
            }
        }
    }
public:
    EpollServer(int port):port_(port){}
    void Init()
    {
        listenSock_ = Socket::SocketCreate();
        Socket::SocketBind(listenSock_,port_);
        Socket::SocketListen(listenSock_,5);

        epfd_ = epoll_create(128);
        if(epfd_ < 0)
        {
            std::cerr << "epoll create error" << std::endl;
            exit(3);
        }
    }
    void Run()
    {
        AddEvent(listenSock_,EPOLLIN);
        while(true)
        {
            struct epoll_event revs[128];
            int num = epoll_wait(epfd_,revs,128,-1);
            if(num < 0)
            {
                std::cerr << "epoll_wait error" << std::endl;
                continue;
            }
            else if(num == 0)
            {
                std::cout << "timeout..." << std::endl;
                continue;
            }
            else
            {
                HandlerEvent(revs,num);
            }
        }
    }
    ~EpollServer()
    {
        if(listenSock_ >= 0)
            close(listenSock_);
        if(epfd_ >= 0)
            close(epfd_);
    }
};